package com.tianji.remark.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.domain.dto.LikeRecordFormDTO;
import com.tianji.remark.domain.dto.LikedTimesDTO;
import com.tianji.remark.domain.po.LikedRecord;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.service.ILikedRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.tianji.remark.constants.RedisConstants.LIKE_BIZ_KEY_PREFIX;
import static com.tianji.remark.constants.RedisConstants.LIKE_COUNT_KEY_PREFIX;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-10
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LikedRecordRedisServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {
    private final StringRedisTemplate redisTemplate;
    private final RabbitMqHelper rabbitMqHelper;
    @Override
    public void addLikeRecord(LikeRecordFormDTO recordDTO) {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        //2.判断是点赞还是取消点赞
        if (recordDTO.getLiked()){
            //2.1.点赞
            log.info("点赞:{}",recordDTO);
            liked(userId,recordDTO);
        }else {
            //2.2.取消点赞
            log.info("取消点赞:{}",recordDTO);
            unLiked(userId,recordDTO);
        }
        //3.统计点赞数,并将其存入redis中的zset中
        Long size = redisTemplate.opsForSet().size(LIKE_BIZ_KEY_PREFIX + recordDTO.getBizId());
        log.info("点赞数:{}",size);
        if (size != null && size > 0){
            redisTemplate.opsForZSet().add(LIKE_COUNT_KEY_PREFIX + recordDTO.getBizType(),
                    recordDTO.getBizId().toString(),
                    size);
        }
    }

    //Zset: bizType: bizId: count某个类型下某个业务对象被点赞的次数
    //set： bizId，userId ：某个业务对象是否被某个用户点赞
    @Override
    @Transactional
    public void readLikedTimesAndSendMessage(String bizType, Integer maxSize) {
        String key= LIKE_COUNT_KEY_PREFIX + bizType;
        //获取点赞数,每次取maxSize条
        log.info("开始统计点赞数,bizType:{},maxSize:{}",bizType,maxSize);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(key, maxSize);
        if (typedTuples == null || typedTuples.isEmpty()){
            return;
        }
        ArrayList<LikedTimesDTO> list = new ArrayList<>(typedTuples.size());
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            String bizId = tuple.getValue();
            Double count = tuple.getScore();
            log.info("点赞数:{},bizId:{}",count,bizId);
            if (count == null){
                continue;
            }
            int i = count.intValue();
            if ( i== 0 || StringUtils.isBlank(bizId)){
                continue;
            }
            LikedTimesDTO timesDTO = new LikedTimesDTO();
            timesDTO.setBizId(Long.valueOf(bizId));
            timesDTO.setLikedTimes(i);
            list.add(timesDTO);
        }
        log.info("点赞数:{}",list);
        if (CollUtil.isNotEmpty(list)){
            rabbitMqHelper.send(
                    MqConstants.Exchange.LIKE_RECORD_EXCHANGE,
                    StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE,bizType ),
                    list
            );
            log.info("点赞数发送成功");
        }
    }
    @Override
    public Set<Long> isBizLiked(List<Long> bizIds) {
        // 1.获取登录用户id
        Long userId = UserContext.getUser();
        // 2.查询点赞状态
        HashSet<Long> set = new HashSet<>(bizIds.size());
        for (Long bizId : bizIds) {
            Boolean member = redisTemplate.opsForSet().isMember(LIKE_BIZ_KEY_PREFIX + bizId, userId.toString());
            if (BooleanUtil.isTrue(member)){
                set.add(bizId);
            }
        }
        // 3.返回结果
       // return list.stream().map(LikedRecord::getBizId).collect(Collectors.toSet());
        return set;
    }

    @Override
    @Transactional
    public void sendToMySQL(String bizType, Integer maxSize) {
        //1.先查询zset获取member中的业务id
        String key = LIKE_COUNT_KEY_PREFIX + bizType;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(key, maxSize);
        if (CollUtil.isEmpty(typedTuples)){
            return;
        }
        HashSet<Long> set = new HashSet<>();//此时获取的set集合中的业务id的业务类型都相同，都为bizType
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples){
            String bizId = tuple.getValue();
            if (StringUtils.isNotBlank(bizId) && bizId!=null){
                set.add(Long.valueOf(bizId));
            }
        }
        //2.根据业务id查询set中的点赞记录
        Set<LikedRecord> likedRecords = new HashSet<>();
        for (Long bizId : set) {
            String key1 = LIKE_BIZ_KEY_PREFIX + bizId;
            Set<String> members = redisTemplate.opsForSet().members(key1);
            if (CollUtil.isNotEmpty(members)){
                if (members != null) {
                    for (String member : members) {
                        //3.将点赞记录存入mysql
                        LikedRecord likedRecord = new LikedRecord();
                        likedRecord.setBizId(bizId);
                        likedRecord.setBizType(bizType);
                        likedRecord.setUserId(Long.valueOf(member));
                        likedRecords.add(likedRecord);
                    }
                }
            }
        }
        //4.查询数据库中的点赞记录
        Set<String> existingKeys = new HashSet<>();
        List<LikedRecord> existingRecords = this.lambdaQuery()
                .in(LikedRecord::getBizId, likedRecords.stream().map(LikedRecord::getBizId).collect(Collectors.toList()))
                .list();
        existingRecords.forEach(record -> existingKeys.add(record.getBizId() + "-" + record.getUserId()));
        List<LikedRecord> filteredRecords = likedRecords.stream()
                .filter(record -> !existingKeys.contains(record.getBizId() + "-" + record.getUserId()))
                .collect(Collectors.toList());
        if (!filteredRecords.isEmpty()) {
            this.saveBatch(filteredRecords);
        }
    }

    void unLiked(Long userId, LikeRecordFormDTO recordDTO) {
        String key = LIKE_BIZ_KEY_PREFIX + recordDTO.getBizId();
          redisTemplate.opsForSet().remove(key, userId.toString());
     }
    private void liked(Long userId, LikeRecordFormDTO recordDTO) {
        String key = LIKE_BIZ_KEY_PREFIX + recordDTO.getBizId();
        //将数据添加到redis中
        redisTemplate.opsForSet().add(key, userId.toString());
    }
}




























